package com.wteam.dragon.system.apps.generator.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wteam.dragon.system.apps.generator.mapper.ColumnInfoMapper;
import com.wteam.dragon.system.apps.generator.mapper.GenConfigMapper;
import com.wteam.dragon.system.apps.generator.mapper.TableInfoDtoMapper;
import com.wteam.dragon.system.apps.generator.pojo.bean.ColumnInfo;
import com.wteam.dragon.system.apps.generator.pojo.bean.GenConfig;
import com.wteam.dragon.system.apps.generator.pojo.dto.ColumnInfoDto;
import com.wteam.dragon.system.apps.generator.pojo.dto.TableInfoDto;
import com.wteam.dragon.system.apps.generator.service.GeneratorService;
import com.wteam.dragon.system.apps.generator.util.GenUtil;
import com.wteam.dragon.system.basebean.bean.ResultMessage;
import com.wteam.dragon.system.exception.BadRequestException;
import com.wteam.dragon.system.util.ListPageUtil;
import com.wteam.dragon.system.util.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author 陈晓辉
 * @Date 2021/5/28 9:54
 */
@Service
@RequiredArgsConstructor
public class GeneratorServiceImpl implements GeneratorService {
    private final TableInfoDtoMapper tableInfoDtoMapper;
    private final ColumnInfoMapper columnInfoMapper;
    private final GenConfigMapper genConfigMapper;

    @Override
    public ResultMessage generator(String tableName) {
        GenConfig genConfig = getGenConfigByTableName(tableName);
        if (genConfig == null) {
            throw new BadRequestException("请先配置生成器");
        }
        try {
            GenUtil.generatorCode(listColumnsByTableName(tableName), genConfig);
        } catch (IOException e) {
            throw new BadRequestException("生成失败，请手动处理已生成的文件");
        }
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("生成代码成功");
        return resultMessage;
    }

    @Override
    public ResultMessage pageTables(Page<TableInfoDto> page, String tableName) {
        List<TableInfoDto> tableInfoDtoList = tableInfoDtoMapper.listTables(tableName);
        ListPageUtil.dealPageList(page, tableInfoDtoList);
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("tableInfoDtoPage", page);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    public ResultMessage listColumns(String tableName) {
        List<ColumnInfo> columnInfoList = listColumnsByTableName(tableName);
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("columnInfoList", columnInfoList);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editColumns(List<ColumnInfo> list) {
        list.forEach(columnInfoMapper::updateById);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更新成功");
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage syncColumns(String tableName) {
        List<ColumnInfo> columnInfoList = listColumnsByTableName(tableName);
        List<ColumnInfo> columnsByMysql = listColumnsByMysql(tableName);
        // 第一种情况，数据库类字段改变或者新增字段
        for (ColumnInfo columnInfo : columnsByMysql) {
            // 根据字段名称查找
            List<ColumnInfo> columns = columnInfoList.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
            // 如果能找到，就修改部分可能被字段
            if (CollectionUtil.isNotEmpty(columns)) {
                ColumnInfo column = columns.get(0);
                column.setColumnType(columnInfo.getColumnType());
                column.setExtra(columnInfo.getExtra());
                column.setKeyType(columnInfo.getKeyType());
                if (StringUtils.isBlank(column.getRemark())) {
                    column.setRemark(columnInfo.getRemark());
                }
                columnInfoMapper.updateById(column);
            } else {
                // 如果找不到，则保存新字段信息
                columnInfoMapper.insert(columnInfo);
            }
        }
        // 第二种情况，数据库字段删除了
        for (ColumnInfo columnInfo : columnInfoList) {
            // 根据字段名称查找
            List<ColumnInfo> columns = columnsByMysql.stream().filter(c -> c.getColumnName().equals(columnInfo.getColumnName())).collect(Collectors.toList());
            // 如果找不到，就代表字段被删除了，则需要删除该字段
            if (CollectionUtil.isEmpty(columns)) {
                columnInfoMapper.deleteById(columnInfo.getId());
            }
        }
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("同步成功");
        return resultMessage;
    }

    private List<ColumnInfo> listColumnsByTableName(String tableName){
        QueryWrapper<ColumnInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ColumnInfo::getTableName, tableName);
        List<ColumnInfo> columnInfoList = columnInfoMapper.selectList(queryWrapper);
        if(columnInfoList.size() == 0){
            columnInfoList = listColumnsByMysql(tableName);
            columnInfoList.forEach(columnInfoMapper::insert);
        }
        return columnInfoList;
    }

    private List<ColumnInfo> listColumnsByMysql(String tableName) {
        List<ColumnInfoDto> result = columnInfoMapper.listColumns(tableName);
        List<ColumnInfo> columnInfoList = new ArrayList<>();
        for (ColumnInfoDto columnInfoDto : result) {
            columnInfoList.add(
                    new ColumnInfo(
                            tableName,
                            columnInfoDto.getColumnName(),
                            "NO".equals(columnInfoDto.getIsNullable()),
                            columnInfoDto.getDataType(),
                            columnInfoDto.getColumnComment(),
                            columnInfoDto.getColumnKey(),
                            columnInfoDto.getExtra()));
        }
        return columnInfoList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editGenConfig(GenConfig genConfig) {
        QueryWrapper<GenConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(GenConfig::getTableName, genConfig.getTableName());
        Integer count = genConfigMapper.selectCount(queryWrapper);
        if(count == 0){
            genConfigMapper.insert(genConfig);
        }else {
            genConfigMapper.updateById(genConfig);
        }
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更改成功");
        return resultMessage;
    }

    @Override
    public ResultMessage getGenConfig(String tableName) {
        GenConfig genConfig = getGenConfigByTableName(tableName);
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("genConfig", genConfig);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    private GenConfig getGenConfigByTableName(String tableName){
        QueryWrapper<GenConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(GenConfig::getTableName, tableName);
        return genConfigMapper.selectOne(queryWrapper);
    }
}
